#include "StdAfx.h"
#include "ViewFrustrum.h"
#include "BoundingVolume.h"


///////////////////////////////////////////////////////////////////////////////

CViewFrustrum::CViewFrustrum(const D3DXMATRIX& mtxView,
                             const D3DXMATRIX& mtxProjection)
      : m_mtxView(mtxView), 
      m_mtxProjection(mtxProjection)
{
}

///////////////////////////////////////////////////////////////////////////////

bool CViewFrustrum::isInside(const AABoundingBox& boundingBox) const
{
   Plane planes[6];
   extractFrustrumPlanes(planes);

   for (int i = 0; i < 6; i++)
   {
      D3DXVECTOR3 nearPoint = findNearPoint(planes[i], boundingBox);

      if ((D3DXVec3Dot(&(planes[i].normal), &nearPoint) + planes[i].distance) > 0)
      {
         return false;
      }
   }

   return true;
}

///////////////////////////////////////////////////////////////////////////////

D3DXVECTOR3 CViewFrustrum::findNearPoint(const Plane& plane, 
                                         const AABoundingBox& boundingBox) const
{
   D3DXVECTOR3 nearPoint;

   if (plane.normal.x < 0)
   {
      nearPoint.x = boundingBox.max.x;
   }
   else
   {
      nearPoint.x = boundingBox.min.x;
   }

   if (plane.normal.y < 0)
   {
      nearPoint.y = boundingBox.max.y;
   }
   else
   {
      nearPoint.y = boundingBox.min.y;
   }

   if (plane.normal.z < 0)
   {
      nearPoint.z = boundingBox.max.z;
   }
   else
   {
      nearPoint.z = boundingBox.min.z;
   }

   return nearPoint;
}

///////////////////////////////////////////////////////////////////////////////

void CViewFrustrum::extractFrustrumPlanes(Plane* planes) const
{
   // transform the planes to the world space (right now they're in the view space)
   D3DXMATRIX wsProjMtx;
   D3DXMatrixMultiply(&wsProjMtx, &m_mtxView, &m_mtxProjection);

   // left plane
   planes[0].normal.x = -(wsProjMtx._14 - wsProjMtx._11);
   planes[0].normal.y = -(wsProjMtx._24 - wsProjMtx._21);
   planes[0].normal.z = -(wsProjMtx._34 - wsProjMtx._31);
   planes[0].distance = -(wsProjMtx._44 - wsProjMtx._41);

   // right plane
   planes[1].normal.x = -(wsProjMtx._14 + wsProjMtx._11);
   planes[1].normal.y = -(wsProjMtx._24 + wsProjMtx._21);
   planes[1].normal.z = -(wsProjMtx._34 + wsProjMtx._31);
   planes[1].distance = -(wsProjMtx._44 + wsProjMtx._41);

   // top plane
   planes[2].normal.x = -(wsProjMtx._14 - wsProjMtx._12);
   planes[2].normal.y = -(wsProjMtx._24 - wsProjMtx._22);
   planes[2].normal.z = -(wsProjMtx._34 - wsProjMtx._32);
   planes[2].distance = -(wsProjMtx._44 - wsProjMtx._42);

   // bottom plane
   planes[3].normal.x = -(wsProjMtx._14 - wsProjMtx._12);
   planes[3].normal.y = -(wsProjMtx._24 - wsProjMtx._22);
   planes[3].normal.z = -(wsProjMtx._34 - wsProjMtx._32);
   planes[3].distance = -(wsProjMtx._44 - wsProjMtx._42);

   // far plane
   planes[4].normal.x = -(wsProjMtx._14 - wsProjMtx._13);
   planes[4].normal.y = -(wsProjMtx._24 - wsProjMtx._23);
   planes[4].normal.z = -(wsProjMtx._34 - wsProjMtx._33);
   planes[4].distance = -(wsProjMtx._44 - wsProjMtx._43);

   // near plane
   planes[5].normal.x = -wsProjMtx._13;
   planes[5].normal.y = -wsProjMtx._23;
   planes[5].normal.z = -wsProjMtx._33;
   planes[5].distance = -wsProjMtx._43;

   // normalize planes
   for (int i = 0; i < 6; i++)
   {
      float length = D3DXVec3Length(&(planes[i].normal));
      planes[i].normal.x /= length;
      planes[i].normal.y /= length;
      planes[i].normal.z /= length;
      planes[i].distance /= length;
   }

}

///////////////////////////////////////////////////////////////////////////////
